package AbstractTests;

import static org.junit.Assert.assertTrue;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import Impl.Dir;
import Impl.Terrain;
import Impl.Type;
import Services.MoteurJeuService;
import Services.TerrainService;

public abstract class AbstractPaireTransitionTest {
	private MoteurJeuService moteur;
	private TerrainService terrain;
	
	public AbstractPaireTransitionTest() {
		moteur = null;
		terrain = null;
	}
	
	protected final MoteurJeuService getMoteur() {
		return moteur;
	}
	protected final TerrainService getTerrain() {
		return terrain;
	}
		
	protected final void setMoteur(MoteurJeuService moteur) {
		this.moteur = moteur;
	}
	protected final void setTerrain(TerrainService terrain) {
		this.terrain = terrain;
	}

	@Before
	public abstract void beforeTests(); 

	@After
	public final void afterTests() {
		moteur = null;
		terrain = null;
	}
	
	
	// BLOC
	// vide, n'a qu'un seul operateur
	
	
	
	
	// TERRAIN
	@Test	// ajout d'objet et start()
	public void testPaire_1(){
		terrain.init(3, 3);
		TerrainService terrainAtPre = new Terrain();
		terrainAtPre.clone(terrain);
		
		terrain.addObject(2, 2, Type.Diamant);
		terrain.addObject(2, 3, Type.SortieFermee);
		terrain.startTerrain();
		
		assertTrue(terrain.isStarted());
		assertTrue(terrain.getXJoueur()==terrainAtPre.getXJoueur());
		assertTrue(terrain.getYJoueur()==terrainAtPre.getYJoueur());
		assertTrue(terrain.getNbJoueur()==terrainAtPre.getNbJoueur());
		assertTrue(terrain.getNbDiamant()==terrainAtPre.getNbDiamant()+1);
		assertTrue(terrain.getNbPorte()==terrainAtPre.getNbPorte()+1);
		
		terrainAtPre.getBloc(2, 2).ChangeType(Type.Diamant);
		terrainAtPre.getBloc(2, 3).ChangeType(Type.SortieFermee);
		for(int x=1; x<=terrain.getSizeX(); x++)
			for(int y=1; y<=terrain.getSizeY(); y++)
				assertTrue(terrain.getBloc(x,y).equals(terrainAtPre.getBloc(x, y)));
		
		for(int x=1; x<=terrain.getSizeX(); x++)
			for(int y=1; y<=terrain.getSizeY(); y++)
				assertTrue(terrain.isChanged(x,y)==terrainAtPre.isChanged(x, y));
	}
	@Test // Ajout d'objet + changement de case du hero
	public void testPaire_2(){
		terrain.init(3, 3);
		TerrainService terrainAtPre = new Terrain();
		terrainAtPre.clone(terrain);
		
		terrain.addObject(2, 2, Type.Diamant);
		terrain.putHero(3, 3);
		
		assertTrue(!terrain.isStarted());
		assertTrue(terrain.getXJoueur()==3);
		assertTrue(terrain.getYJoueur()==3);
		assertTrue(terrain.getNbJoueur()==terrainAtPre.getNbJoueur());
		assertTrue(terrain.getNbDiamant()==terrainAtPre.getNbDiamant()+1);
		assertTrue(terrain.getNbPorte()==terrainAtPre.getNbPorte());
		
		terrainAtPre.getBloc(3, 3).ChangeType(Type.Hero);
		terrainAtPre.getBloc(1, 1).ChangeType(Type.Vide);
		terrainAtPre.getBloc(2, 2).ChangeType(Type.Diamant);
		for(int x=1; x<=terrain.getSizeX(); x++)
			for(int y=1; y<=terrain.getSizeY(); y++)
				assertTrue(terrain.getBloc(x,y).equals(terrainAtPre.getBloc(x, y)));
		
		for(int x=1; x<=terrain.getSizeX(); x++)
			for(int y=1; y<=terrain.getSizeY(); y++)
				assertTrue(terrain.isChanged(x,y)==terrainAtPre.isChanged(x, y));
	}
	@Test	// changement de place du hero + ajout d'objet
	public void testPaire_3(){
		terrain.init(3, 3);
		TerrainService terrainAtPre = new Terrain();
		terrainAtPre.clone(terrain);
		
		
		terrain.putHero(3, 3);
		terrain.addObject(2, 2, Type.Diamant);
		
		assertTrue(!terrain.isStarted());
		assertTrue(terrain.getXJoueur()==3);
		assertTrue(terrain.getYJoueur()==3);
		assertTrue(terrain.getNbJoueur()==terrainAtPre.getNbJoueur());
		assertTrue(terrain.getNbDiamant()==terrainAtPre.getNbDiamant()+1);
		assertTrue(terrain.getNbPorte()==terrainAtPre.getNbPorte());
		
		terrainAtPre.getBloc(3, 3).ChangeType(Type.Hero);
		terrainAtPre.getBloc(1, 1).ChangeType(Type.Vide);
		terrainAtPre.getBloc(2, 2).ChangeType(Type.Diamant);
		for(int x=1; x<=terrain.getSizeX(); x++)
			for(int y=1; y<=terrain.getSizeY(); y++)
				assertTrue(terrain.getBloc(x,y).equals(terrainAtPre.getBloc(x, y)));
		
		for(int x=1; x<=terrain.getSizeX(); x++)
			for(int y=1; y<=terrain.getSizeY(); y++)
				assertTrue(terrain.isChanged(x,y)==terrainAtPre.isChanged(x, y));
	}
	@Test	// ce test est ternaire mais start + mouvement hero
	public void testPaire_4(){
		terrain.init(3, 3);
		terrain.addObject(2, 2, Type.Diamant);
		terrain.addObject(2, 3, Type.SortieFermee);
		TerrainService terrainAtPre = new Terrain();
		terrainAtPre.clone(terrain);
		
		terrain.startTerrain();
		terrain.putHero(3, 1);
		

		assertTrue(terrain.isStarted());
		assertTrue(terrain.getXJoueur()==3);
		assertTrue(terrain.getYJoueur()==1);
		assertTrue(terrain.getNbJoueur()==terrainAtPre.getNbJoueur());
		assertTrue(terrain.getNbDiamant()==terrainAtPre.getNbDiamant());
		assertTrue(terrain.getNbPorte()==terrainAtPre.getNbPorte());
		
		terrainAtPre.getBloc(1, 1).ChangeType(Type.Vide);
		terrainAtPre.getBloc(3, 1).ChangeType(Type.Hero);
		for(int x=1; x<=terrain.getSizeX(); x++)
			for(int y=1; y<=terrain.getSizeY(); y++)
				assertTrue(terrain.getBloc(x,y).equals(terrainAtPre.getBloc(x, y)));
		
		for(int x=1; x<=terrain.getSizeX(); x++)
			for(int y=1; y<=terrain.getSizeY(); y++)
				assertTrue(terrain.isChanged(x,y)==terrainAtPre.isChanged(x, y));
	}
	@Test // putHero + moveObject
	public void testPaire_5(){
		terrain.init(3, 3);
		terrain.addObject(2, 2, Type.Diamant);
		terrain.addObject(2, 3, Type.SortieFermee);
		terrain.startTerrain();
		TerrainService terrainAtPre = new Terrain();
		terrainAtPre.clone(terrain);
		
		terrain.putHero(3, 1);
		terrain.moveObject(2, 2, 2, 1);

		assertTrue(terrain.isStarted());
		assertTrue(terrain.getXJoueur()==3);
		assertTrue(terrain.getYJoueur()==1);
		assertTrue(terrain.getNbJoueur()==terrainAtPre.getNbJoueur());
		assertTrue(terrain.getNbDiamant()==terrainAtPre.getNbDiamant());
		assertTrue(terrain.getNbPorte()==terrainAtPre.getNbPorte());
		
		terrainAtPre.getBloc(1, 1).ChangeType(Type.Vide);
		terrainAtPre.getBloc(3, 1).ChangeType(Type.Hero);
		terrainAtPre.getBloc(2, 2).ChangeType(Type.Vide);
		terrainAtPre.getBloc(2, 1).ChangeType(Type.Diamant);
		for(int x=1; x<=terrain.getSizeX(); x++)
			for(int y=1; y<=terrain.getSizeY(); y++)
				assertTrue(terrain.getBloc(x,y).equals(terrainAtPre.getBloc(x, y)));
		
		for(int x=1; x<=terrain.getSizeX(); x++){
			for(int y=1; y<=terrain.getSizeY(); y++){
				if(x==2 && y==1)
					assertTrue(terrain.isChanged(x,y));
				else 
					assertTrue(terrain.isChanged(x,y)==terrainAtPre.isChanged(x, y));
	
			}
		}
	}
	
	
	// MOTEUR JEU
	@Test
	public void testPaire_10(){
		terrain.init(3, 3);
		terrain.addObject(2, 2, Type.Diamant);
		terrain.addObject(2, 3, Type.SortieFermee);
		terrain.startTerrain();
		moteur.init(5, terrain);
		
		moteur.moveHero(Dir.Gauche);
		moteur.moveObjects();
		
		assertTrue(moteur.estFinie()==false);
		assertTrue(moteur.estGagne()==false);
		assertTrue(moteur.haveHeroMove()==true);
		assertTrue(moteur.haveObjectMove()==true);
		assertTrue(moteur.getPasRestants()==4);
		assertTrue(moteur.getTerrain().equals(terrain));
	}
	@Test 		// Ce Test est ternaire mais bon a prendre...
	public void testPaire_11(){
		terrain.init(3, 3);
		terrain.addObject(2, 2, Type.Diamant);
		terrain.addObject(2, 3, Type.SortieFermee);
		terrain.startTerrain();
		moteur.init(5, terrain);
		
		moteur.moveHero(Dir.Gauche);
		moteur.moveObjects();
		moteur.verif();
		
		assertTrue(moteur.estFinie()==false);
		assertTrue(moteur.estGagne()==false);
		assertTrue(moteur.haveHeroMove()==false);
		assertTrue(moteur.haveObjectMove()==false);
		assertTrue(moteur.getPasRestants()==4);
		assertTrue(moteur.getTerrain().equals(terrain));
	}
}
